package org.bultreebank.indexing;


import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.bultreebank.document_repository.impl.IndexesDocumentsImpl;
import org.bultreebank.document_repository.interfaces.IndexesDocumentsManager;
import org.bultreebank.index.schema.management.impl.SearchEngineField;
import org.bultreebank.index.schema.management.interfaces.IndexContextsManager;
import org.bultreebank.index.schema.management.interfaces.IndexingSchemaManager;
import org.bultreebank.index.utils.Constants;
import org.bultreebank.index.utils.Factory;
import org.bultreebank.index.utils.SearchUtils;
import org.bultreebank.index.utils.Utils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import clark.dom.impl.DOMFactory;
import clark.statistics.NodeInfo;
import clark.xpath.MainXPath;



public class IndexImpl implements IndexManager, Constants{

	/**
	 * writer for adding documents
	 */
	private String indexID;
	private boolean hasContextFieldsToIndex;
	 
	private Map<String, IndexWriter> contextWriters = new HashMap<String, IndexWriter>();
	private Map<String, List<SearchEngineField>> contextFields = new HashMap<String, List<SearchEngineField>>();
	private Document reportDoc;
	private static IndexWriter writer;
	private static IndexReader reader;	
	private Set<Field> reusable = new HashSet<Field>(); 
	private IndexesDocumentsManager documentsManager;
	private IndexContextsManager contextsManager;
	private IndexingSchemaManager indexManager;
	private Map<String, String> indexAnalyzersMap;
	private String currentLang;
	private Analyzer analyzer;
	private Stack<String> parentIDs = new Stack<String>();
	private Stack<String> parentXPaths = new Stack<String>();
	public IndexImpl(Map<String, String> indexAnalyzersMap, IndexContextsManager contextsManager, IndexesDocumentsManager documentsManager) throws Exception//IndexingSchemaInterface indexManager) throws Exception
	{
		this.indexAnalyzersMap = indexAnalyzersMap;
		if (indexAnalyzersMap.size() == 1)
		{
			currentLang = indexAnalyzersMap.keySet().iterator().next();
			String className = indexAnalyzersMap.get(currentLang);
			analyzer = (Analyzer)Factory.createInstance(className);
		}
		indexManager = ((IndexesDocumentsImpl)documentsManager).getIndexSchemaManager();
		this.contextsManager = contextsManager;
		this.documentsManager = documentsManager;
	}
	private void setIndexSchema(String indexID) throws Exception
	{
		Document indexSchema = indexManager.getIndexSchema(indexID);
		contextsManager.setIndexSchemaDocument(indexSchema);
	}
	/**
	 * Adds the document with the specified document ID to the specified index
	 * @param docID - document ID of a document available in the Search
	 *  Engine Document Repository if it exists 
	 * @param usersIndexID - user defined indexID
	 * @throws Exception
	 */
	public void indexDocument(String docID, Document metadataDocument, 
			String indexID, boolean returnReport) throws Exception 
	{
		boolean hasGlobalFields = false;
		Element reportElem =  null;
		Element docElem = null;
		
		if (returnReport)
			reportElem = reportDoc.getDocumentElement();	
		if (returnReport)
		{
			docElem = reportDoc.createElement("document");
			reportElem.appendChild(docElem);
		}
		Date startDate = new Date();
		long start = startDate.getTime();
		if (!indexManager.ifIndexExists(indexID))
			throw new Exception ("The index " + indexID + " doesn't exist!");
		String internalIndexID = indexManager.getInternalIndexID(indexID);
		setIndexSchema(indexID);
		boolean isUpdateMode = false;
		String internalDocID = documentsManager.getInternalDocID(docID);
		if (internalDocID == null)
			throw new Exception ("A document with the specified docID: " + docID + " doesn't exist in the Search Engine repository!");
		List<String> docsForIndex =  documentsManager.getDocsForIndex(indexID);
		Document xmlDocument = documentsManager.retrieveDocument(docID);
		if (docsForIndex != null && docsForIndex.contains(docID))
			isUpdateMode = true;
		Element metaRoot = null;
		if (returnReport)
		{
			docElem.setAttribute("starting", startDate.toString());
			docElem.setAttribute(DOC_ID, docID);
			docElem.setAttribute("num_tokens", String.valueOf(Utils.docLength(xmlDocument)));
		}
		if (metadataDocument != null)
		{
			contextsManager.addMetadataContextFields(metadataDocument);
			metaRoot = metadataDocument.getDocumentElement();
		}
		List<SearchEngineField> globalFields = contextsManager.
			getGlobalFields();
		
		clearReusableObjects(indexID);
		
		String lang = indexManager.getLang(indexID);
		if (!this.indexAnalyzersMap.containsKey(lang))
			lang = "en";
		indexInGlobalDocIndex(lang, globalFields, internalIndexID, indexID,
				docID,internalDocID, xmlDocument, metaRoot, isUpdateMode);
		
		List<Node> contexts = contextsManager.getIndexSchemaRootContexts();
		
		indexContextFields(lang, contexts, xmlDocument,
				internalDocID, internalIndexID,
				isUpdateMode);
		clearReusableObjects(indexID);
		if (hasGlobalFields || hasContextFieldsToIndex)
		{
			documentsManager.addDocumentToIndex(docID, indexID);
			Date endDate = new Date();
			long end = endDate.getTime();
			if (returnReport)
			{
				docElem.setAttribute("ending", endDate.toString());
				docElem.setAttribute("period", String.valueOf(end - start));
				Utils.saveDocument("Test/index_report_text.xml", reportDoc, "UTF-8");
			}
		}
		else
		{
			hasContextFieldsToIndex = false;
			throw new Exception("The indexing schema does not comply with the XML document structure!\nThe document is not added because there are not any fields to index!");
		}
		
		
	}

	private void clearReusableObjects(String indexID) throws Exception
	{
		if(this.indexID == null || !this.indexID.equals(indexID))
		{
			reusable.clear();
			Iterator<IndexWriter> writersIter = contextWriters.values().iterator();
			while(writersIter.hasNext())
				closeWriter(writersIter.next());
			contextWriters.clear();
			contextFields.clear();
			closeWriter(writer);
		}
			
	}
	
	/**
	 * Adds the document specified to the index and saves it in the Search
	 * engine document repository if it exists. The document identifier for 
	 * the XML document to index is determined by the following priority order:
	 * 	1) explicitly defined document ID
	 * 	2) metadata document
	 * 	3) indexing schema field
	 * If no docID is specified an Exception is thrown
	 * @param xmlDocument - an XML document to index
	 * @param metadataDocument - a metadata document containing additional info 
	 * for the XML document to index
	 * @param indexID - user defined index ID
	 * @param docID - explicitly defined document ID
	 * @return
	 * @throws Exception
	 */
	public void indexDocument(
			Document xmlDocument,
			Document metadataDocument, String indexID, String docID,
			boolean returnReport)
			throws Exception
	{
		boolean hasGlobalFields = false;
		
		Element docElem =  null;
		Element reportElem = null;
		if (returnReport)
		{
			if (reportDoc == null)
			{
				reportDoc = DOMFactory.getEmptyDocument();
				reportElem = reportDoc.createElement("root");
				reportDoc.appendChild(reportElem);
			}
		
			reportElem = reportDoc.getDocumentElement();
		}
		if (returnReport)
		{
			docElem = reportDoc.createElement("document");
			reportElem.appendChild(docElem);
		}
		Date startDate = new Date();
		long start = startDate.getTime();
				
		if (!indexManager.ifIndexExists(indexID))
			throw new Exception ("The index " + indexID + " doesn't exist!");
		String internalIndexID = indexManager.getInternalIndexID(indexID);
		setIndexSchema(indexID);
		String internalDocID = null;
		boolean isUpdateMode = false;
		docID = getDocID(xmlDocument, metadataDocument, indexID, docID);
		if (returnReport)
		{
			//docElem.setAttribute("starting", startDate.toString());
			docElem.setAttribute(DOC_ID, docID);
			docElem.setAttribute("num_tokens", String.valueOf(Utils.docLength(xmlDocument)));
		}
		List<String> docsForIndex =  documentsManager.getDocsForIndex(indexID);
		if (docsForIndex != null && docsForIndex.contains(docID))
			isUpdateMode = true;
		internalDocID = Utils.getAvailableInternalID(SYSTEM_FILE_PREFIX, 
				docID, 
				documentsManager.getAllUser_SystemDocs());
		Element metaRoot = null;
		if (metadataDocument != null)
		{	
			contextsManager.addMetadataContextFields(metadataDocument);
			metaRoot = metadataDocument.getDocumentElement();
		}
		List<SearchEngineField> globalFields = contextsManager.
			getGlobalFields();
		
		clearReusableObjects(indexID);
		String lang = indexManager.getLang(indexID);
		if (!this.indexAnalyzersMap.containsKey(lang))
			lang = "en";
		hasGlobalFields = indexInGlobalDocIndex(lang, globalFields, internalIndexID, indexID,
				docID,internalDocID, xmlDocument, metaRoot, isUpdateMode);
		List<Node> contexts = contextsManager.getIndexSchemaRootContexts();
		indexContextFields(lang, contexts, xmlDocument,
				internalDocID, internalIndexID,
				isUpdateMode);
		clearReusableObjects(indexID);
		if (hasGlobalFields || hasContextFieldsToIndex)
		{
			if (isUpdateMode)
				documentsManager.updateDocumentToIndex(docID, indexID, xmlDocument);
			else
				documentsManager.addDocumentToIndex(docID, internalDocID,
					indexID, xmlDocument);
		
			Date endDate = new Date();
			long end = endDate.getTime();
			if (returnReport)
			{
				//docElem.setAttribute("ending", endDate.toString());
				docElem.setAttribute("period", String.valueOf((double)(end - start)/1000));
				Utils.saveDocument("Test/result_contexts.xml", reportDoc, "UTF-8");
			}
		}
		else
		{

			hasContextFieldsToIndex = false;
			throw new Exception("The indexing schema does not comply with the XML document structure!\nThe document is not added because there are not any fields to index!");
		}
		
	}
	public void deleteDocFromIndex(String docID, String indexID) throws Exception {
		if (!indexManager.ifIndexExists(indexID))
			throw new Exception ("The index " + indexID + " doesn't exist!");
		String internalDocID = documentsManager.getInternalDocID(docID);
		if (internalDocID == null || internalDocID.equals(EMPTY_STR))
			return;
		
		Map<String, List<String>> realIndexesMap = getAllContextDocs(internalDocID,
				indexID);
		Iterator<String> iter = realIndexesMap.keySet().iterator();
		while (iter.hasNext())
		{
			String indexPath = iter.next();
			reader = SearchUtils.openReader(indexPath);
			List<String> docIDs = realIndexesMap.get(indexPath);
			for(String doc:docIDs)
			{
				if (doc.startsWith(internalDocID) || doc.startsWith(docID))
				{
						Term term = null;
						if (indexPath.substring(indexPath.lastIndexOf(SEPARATOR) + 1).equals(GLOBAL_CONTEXT))
							term = new Term(DOC_ID, docID);
						else
							term = new Term(DOC_ID, doc);
						int deleted = reader.deleteDocuments(term);
						if (deleted < 1)
							throw new Exception("The document: " + docID + " couldn't be deleted from index: " + indexID + "!");
				}
			}
			reader.close();
			
		}
		
	}
	private Map<String, List<String>> getAllContextDocs(String internalDocID, String indexID) throws Exception
	{
		Map<String, List<String>> result = new HashMap<String, List<String>>();
		setIndexSchema(indexID);
		List<Node> contexts = contextsManager.getIndexSchemaContexts();//.getContextInternalIDsMap(indexSchema);
		String internalIndexID = indexManager.getInternalIndexID(indexID);
	
		for (int j = 0; j < contexts.size(); j++)
		{
			Element elem = (Element) contexts.get(j);
			String contextID = elem.getAttribute(INDEX_ID);
			String path = indexManager.getIndexRepositoryPath() + 
			SEPARATOR + internalIndexID + SEPARATOR + contextID; 
			reader = SearchUtils.openReader(path);
			int docsNum = reader.numDocs();
			List<String> temp = new ArrayList<String>();
			for (int i = 0; i < docsNum; i++)
			{
				if (!IndexReader.isLocked(path) && !reader.isDeleted(i))
					temp.add(reader.document(i).get(DOC_ID));
			}
			result.put(path, temp);
			reader.close();
		}
		String path = indexManager.getIndexRepositoryPath() + 
		SEPARATOR + internalIndexID + SEPARATOR + GLOBAL_CONTEXT;
		reader = SearchUtils.openReader(path);
		int docsNum = reader.numDocs();
		List<String> temp = new ArrayList<String>();
		for (int i = 0; i < docsNum; i++)
		{
			if (!reader.isDeleted(i))
			{
				String documentID = reader.document(i).get(DOC_ID);
				if (!temp.contains(documentID))
					temp.add(documentID);
			}
			
		}
		result.put(path, temp);
		reader.close();
		return result;
	}
	
	private boolean indexInGlobalDocIndex(String lang, List<SearchEngineField> globalFields,
			String internalIndexID, String indexID, String docID, 
			String internalDocID, Document xmlDocument,
			Element metaRoot, boolean isUpdateMode)
	throws Exception
	{
		org.apache.lucene.document.Document luceneDoc = 
			new org.apache.lucene.document.Document();
		String indexDocumentDIR = indexManager.getIndexRepositoryPath() + 
		SEPARATOR + internalIndexID + SEPARATOR + GLOBAL_CONTEXT;
		
		addFieldsToGlobalContext(globalFields, xmlDocument.getDocumentElement(),
				metaRoot,
				luceneDoc, indexDocumentDIR);
		boolean hasNoFields = luceneDoc.getFields().isEmpty();
		if (!hasNoFields)
		{
			luceneDoc.add(createField(false, false, true, DOC_ID, internalDocID));

			initWriter(indexDocumentDIR, lang);
			if (isUpdateMode)
				updateIndex(internalDocID, luceneDoc, writer);
			else
				addToIndex(luceneDoc, writer);
		
			closeWriter(writer);
			writer = null;
		}
		return !hasNoFields;
	}
	
	private String getDocID(Document xmlDocument,
			Document metadataDocument, String indexID, String docID)
	throws Exception
	{
		if (docID != null && !docID.equals(EMPTY_STR))
			return docID;
		if (metadataDocument != null)
		{
			String docIDMetaAttr = metadataDocument.getDocumentElement().
				getAttribute(DOC_ID);
			if (docIDMetaAttr != null && !docIDMetaAttr.equals(EMPTY_STR))
				return docIDMetaAttr;
		}
		setIndexSchema(indexID);
		List<SearchEngineField> globalFields = contextsManager.
		getGlobalFields();
		for (SearchEngineField field:globalFields)
		{
			if (field.getName().equals(DOC_ID))
			{
				List<Node> nodes = MainXPath.processXPath(field.getXPath(),
						xmlDocument.getDocumentElement());
				if (!nodes.isEmpty() && nodes.size() == 1)
				{
					return nodes.get(0).getNodeValue(); 
				}
			}
		}
		throw new Exception("The docID has to be specified explicitally," +
				"in the metadata document or an xpath has to be supplied in the" +
				"indexing schema for a docID extraction on  a global" +
				" (document) context!");
	}
	

	private void addFieldsToGlobalContext(
			List<SearchEngineField> fields,
			Element xmlDocRoot,
			Element  metaRoot, 
			org.apache.lucene.document.Document luceneDoc,
			String indexDIR)
	throws Exception
	{
		for (Iterator<SearchEngineField> iter = fields.iterator(); iter.hasNext(); )
		{
			SearchEngineField field = iter.next();
			String xpath = "//" + field.getXPath();
			if (field.getXPath() == null || field.getXPath().equals(EMPTY_STR))
				xpath = null;
			String name = field.getName();
			boolean isSearchable = field.IsSearchable();
			boolean isRetrievable = field.IsRetrievable();
			boolean isKeyword = field.IsKeyword();
			if (name.equals(DOC_ID))
				continue;
			String fieldValue = null;
			if (xpath != null && !xpath.equals(EMPTY_STR))
			{
				List<Node> values = MainXPath.
				processXPath(xpath, xmlDocRoot);
				fieldValue = Utils.getStringFromNodeList(isSearchable, values);
				if (fieldValue != null && !fieldValue.equals(EMPTY_STR))
				{
					Field luceneField = createField(
							isSearchable, 
							isRetrievable,
							isKeyword,
							name, fieldValue);
					luceneDoc.add(luceneField);
				}
			}
			else if (metaRoot != null)
			{
				fieldValue = metaRoot.getAttribute(name);
				if (fieldValue != null && !fieldValue.equals(EMPTY_STR))
				{
					if (isSearchable)
						fieldValue = Utils.normalizeTerm(fieldValue.
	            			 toLowerCase());
					
					Field luceneField = createField(
							isSearchable, 
							isRetrievable,
							isKeyword,
							name, fieldValue);
					luceneDoc.add(luceneField);
					reusable.add(luceneField);
				}
			}
			
		}
		
	}
	private void adaptIndexWriter(int numDocs, IndexWriter writer)
	{
		if (numDocs > 100)
		{	
			writer.setMergeFactor(numDocs / 10);
			writer.setMaxMergeDocs(numDocs/5 );
		}
	}
	
	
	
	private String initContextWriter(Element contextElem, String internalIndexID, String lang) throws Exception
	{
		String contextIndexID = contextElem.getAttribute(INDEX_ID);
		String indexDIR = indexManager.getIndexRepositoryPath() + 
		SEPARATOR + internalIndexID + SEPARATOR + contextIndexID;
		adjustAnalyzer(lang);
		IndexWriter contextWriter = null;
		if (this.contextWriters.containsKey(indexDIR))
			contextWriter = this.contextWriters.get(indexDIR);
		else
			contextWriter = new IndexWriter(indexDIR,
				analyzer, IndexWriter.MaxFieldLength.UNLIMITED);
		contextWriters.put(indexDIR, contextWriter);
		return indexDIR;
	}
	
	private void indexContextFields(
			String lang,
			List<Node> contexts,
			Document xmlDoc,
			String internalDocID, String internalIndexID,
			boolean isUpdateMode)			
	throws Exception
	{
		
		for (Node context: contexts)
		{
			boolean hasParentContext = false;
			if (context.getParentNode().getNodeName().equals(CONTEXT))
				hasParentContext = true;
			Element contextElem = (Element) context;
			boolean hasFieldsToIndex = false;
			List<Node> fieldElems = MainXPath.processXPath(FIELD, contextElem);
			if (!fieldElems.isEmpty())
				hasFieldsToIndex = true;
			String indexDIR = null;
			if (hasFieldsToIndex)
				indexDIR = initContextWriter(contextElem, internalIndexID, lang);
			String query = null;
			
			String parentXPath = null;
			if (!parentXPaths.isEmpty())
				parentXPath = parentXPaths.pop();
			if (!hasFieldsToIndex && !hasParentContext)
				query = "//" + contextElem.getAttribute( XPATH_ATTRIBUTE);
			else if (!hasParentContext && parentXPath != null)
				query = contextElem.getAttribute(ABSOLUTE_XPATH);
			else if (parentXPath == null)
			    query = contextElem.getAttribute(ABSOLUTE_XPATH);
			else 
				query = parentXPath + LEFT_SLASH + contextElem.getAttribute("xpath");
			if (query != null && !query.equals(EMPTY_STR))
			{
				List<Node> nodes = MainXPath.processXPath(query, 
					xmlDoc.getDocumentElement());
				if (nodes.isEmpty() && !parentIDs.isEmpty())
					parentIDs.pop();
				IndexWriter contextWriter = contextWriters.get(indexDIR);
				if (contextWriter != null)
					adaptIndexWriter(nodes.size(), contextWriter);
				 
				for(int i = 0; i < nodes.size(); i++)
				{
					
					Node node = nodes.get(i);
					String val = NodeInfo.evalXPathExprNew(node);
					
					String docID = null;
					if (internalDocID != null && !internalDocID.equals(EMPTY_STR))
						docID = internalDocID + replaceBrokenBrackets(val);
					
					String parentID = null;
					if (parentIDs.isEmpty())
						parentID = null;
					else if (i < nodes.size() - 1)
						parentID = parentIDs.peek();
					else
						parentID = parentIDs.pop();
					if (parentID != null)
						docID =  parentID + SPEC_CHAR +  docID;
					 if (hasFieldsToIndex)
					{
							
							org.apache.lucene.document.Document luceneDoc = 
							new org.apache.lucene.document.Document();
							for (Field f:reusable)
								luceneDoc.add(f);
											
							List<Node> fields = MainXPath.processXPath(FIELD, context);
							
							for (Node fieldNode:fields)
							{
								Element fieldElem = (Element) fieldNode;
								String name = fieldElem.getAttribute(NAME);
								String xpath = fieldElem.getAttribute(VALUE);
								String retrievable = fieldElem.getAttribute(RETRIEVABLE);
								String searchable = fieldElem.getAttribute(SEARCHABLE);
								String keyword = fieldElem.getAttribute(KEYWORD);
								
								SearchEngineField field = new SearchEngineField(name,
										retrievable,
										searchable, keyword,  xpath);
								
								List <Node> contentNodes = MainXPath.processXPath(xpath,
										node);
								if (contentNodes != null && !contentNodes.isEmpty())
								{
									String fieldContent = Utils.getStringFromNodeList(field.IsSearchable(),
										contentNodes);
								
									luceneDoc.add(createField(field.IsSearchable(),
											field.IsRetrievable(), field.IsKeyword(),
											name , fieldContent));
								}
								
							}
							if (!luceneDoc.getFields().isEmpty())
							{
								hasContextFieldsToIndex = true;
								luceneDoc.add(createField(false,
										false, true,
										DOC_ID , docID));
									if (isUpdateMode)
										updateIndex(docID, luceneDoc, contextWriter);
									else
										addToIndex(luceneDoc, contextWriter);
							}
					}
					
					List<Node> contextChildren = MainXPath.processXPath("context", context);
					if (!contextChildren.isEmpty())
					{
						parentID = docID;
						parentXPath = val.replace("_", LEFT_SLASH);
						for (int j = 0; j < contextChildren.size(); j++)
						{
							parentXPaths.push(parentXPath);
							parentIDs.push(parentID);
						}
						indexContextFields(lang, contextChildren,
								xmlDoc, internalDocID, internalIndexID, isUpdateMode);
					}
											
				}
			}
		}
	
	}
	private String replaceBrokenBrackets(String docID)
	{
		docID = docID.replace("[", "#");
		docID = docID.replace("]", EMPTY_STR);
		return docID;
	}
	
	private Field createField(boolean searchable, boolean retrievable, 
			boolean keyword, String 
			fieldID, String fieldContent)
	{
		if (keyword)
			return new Field(fieldID,
	   				fieldContent,	   
	        		Field.Store.YES, 
	   				Field.Index.NOT_ANALYZED);
		else
		{
			if (retrievable) 
	   		{
	           if (searchable)
	        	    return new Field(fieldID,
	   				fieldContent,	   
	        		Field.Store.YES, 
	   				Field.Index.ANALYZED);
	           else
	        	    return new Field(fieldID,
	          		fieldContent,
		   			Field.Store.YES, 
		   			Field.Index.NO);
	        }
	        else
	        {
	
	        	if (searchable)
	        		return new Field(fieldID,
	         		fieldContent,
	        		Field.Store.NO, 
	   				Field.Index.ANALYZED);
	        	else
	        		return new Field(fieldID,
	    	         		fieldContent,
	    	        		Field.Store.NO, 
	    	   				Field.Index.NO);
	       }
		}
	}

	private void updateIndex(String internalDocID,
			org.apache.lucene.document.Document luceneDocument, IndexWriter writer)
	throws Exception
	{
		Term term = new Term(DOC_ID, internalDocID);
		writer.updateDocument(term,luceneDocument);
	}
	private void addToIndex(org.apache.lucene.document.Document luceneDocument, IndexWriter writer)
	throws Exception
	{
		 writer.addDocument(luceneDocument);
	}
	private void closeWriter(IndexWriter writer)throws Exception
	{
		if (writer != null)
		{
			writer.optimize();
			writer.close();
		}
	}
	
	private void adjustAnalyzer(String lang)
	{
		if (currentLang != null && currentLang.equals(lang))
			return;
		currentLang = lang;
		analyzer = (Analyzer)Factory.createInstance(indexAnalyzersMap.get(lang));
		
	}
	private void initWriter(String indexDIR, String lang) throws Exception
	{
		    try
			  {
				  if (writer != null)
					  writer.close();
				  adjustAnalyzer(lang);
				  writer = new IndexWriter(indexDIR, analyzer, IndexWriter.MaxFieldLength.UNLIMITED); 
			  }
			  catch(Exception e)
			  {
				  if (writer != null)
					  writer.close();
				  throw new Exception("The index is locked!",e);
			  }
	}
	@Override
	public void initIndexingReportDocument() {
		this.reportDoc = DOMFactory.getEmptyDocument();
		Element reportElem = reportDoc.createElement("report");
		reportDoc.appendChild(reportElem);
	}
	@Override
	public Document getIndexingReportDocument()
	{
		return reportDoc;
	}
	@Override
	public void clearIndexingReportDocument() {
		reportDoc = null;
		
	}

	
}
